<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>流媒体服务器</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
    <style>
        body {
            padding-top: 20px;
            padding-bottom: 20px;
        }
        .header {
            padding-bottom: 20px;
            margin-bottom: 30px;
            border-bottom: 1px solid #e5e5e5;
        }
        .video-container {
            margin-bottom: 20px;
        }
        .recording-item {
            margin-bottom: 10px;
            padding: 10px;
            border: 1px solid #dee2e6;
            border-radius: 4px;
        }
        .tab-content {
            padding-top: 20px;
        }
        #playerContainer {
            width: 100%;
            height: 0;
            padding-bottom: 56.25%; /* 16:9宽高比 */
            position: relative;
            background-color: #000;
            margin-bottom: 15px;
        }
        #videoPlayer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h2>流媒体服务器</h2>
            <p class="text-muted">RTMP流媒体服务器，支持视频推流、拉流和录制回放</p>
        </div>

        <ul class="nav nav-tabs" id="myTab" role="tablist">
            <li class="nav-item" role="presentation">
                <button class="nav-link active" id="streams-tab" data-bs-toggle="tab" data-bs-target="#streams" type="button" role="tab" aria-controls="streams" aria-selected="true">在线推流</button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="recordings-tab" data-bs-toggle="tab" data-bs-target="#recordings" type="button" role="tab" aria-controls="recordings" aria-selected="false">录像回放</button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="player-tab" data-bs-toggle="tab" data-bs-target="#player" type="button" role="tab" aria-controls="player" aria-selected="false">视频播放器</button>
            </li>
            <li class="nav-item" role="presentation">
                <button class="nav-link" id="status-tab" data-bs-toggle="tab" data-bs-target="#status" type="button" role="tab" aria-controls="status" aria-selected="false">服务器状态</button>
            </li>
        </ul>

        <div class="tab-content" id="myTabContent">
            <!-- 在线推流流列表 -->
            <div class="tab-pane fade show active" id="streams" role="tabpanel" aria-labelledby="streams-tab">
                <h3>当前在线推流</h3>
                <div class="alert alert-info" id="no-streams" role="alert">
                    当前没有正在进行的推流
                </div>
                <div class="row" id="streams-container"></div>
                <button class="btn btn-primary mt-3" id="refresh-streams">刷新列表</button>
            </div>

            <!-- 录像回放列表 -->
            <div class="tab-pane fade" id="recordings" role="tabpanel" aria-labelledby="recordings-tab">
                <h3>录像回放列表</h3>
                <div class="alert alert-info" id="no-recordings" role="alert">
                    没有可用的录像回放
                </div>
                <div id="recordings-container"></div>
                <button class="btn btn-primary mt-3" id="refresh-recordings">刷新列表</button>
            </div>

            <!-- 视频播放器 -->
            <div class="tab-pane fade" id="player" role="tabpanel" aria-labelledby="player-tab">
                <h3>视频播放器</h3>
                <div class="form-group mb-3">
                    <label for="videoUrl" class="form-label">视频 URL</label>
                    <input type="text" class="form-control" id="videoUrl" placeholder="输入推流流或录像 URL">
                </div>
                <div class="form-group mb-3">
                    <label class="form-label">播放类型</label>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="playerType" id="flvPlayer" value="flv" checked>
                        <label class="form-check-label" for="flvPlayer">FLV (录像回放)</label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="playerType" id="hlsPlayer" value="hls">
                        <label class="form-check-label" for="hlsPlayer">HLS (推流/回放)</label>
                    </div>
                </div>
                <button class="btn btn-primary mb-3" id="playBtn">播放</button>
                <button class="btn btn-secondary mb-3 ms-2" id="stopBtn">停止</button>
                
                <div id="playerContainer">
                    <video id="videoPlayer" controls></video>
                </div>
            </div>

            <!-- 服务器状态 -->
            <div class="tab-pane fade" id="status" role="tabpanel" aria-labelledby="status-tab">
                <h3>服务器状态</h3>
                <div class="card">
                    <div class="card-body">
                        <div id="server-info">加载中...</div>
                    </div>
                </div>
                <button class="btn btn-primary mt-3" id="refresh-status">刷新状态</button>
            </div>
        </div>
    </div>

    <!-- 引入脚本 -->
    <script th:src="@{/js/jquery.min.js}"></script>
    <script th:src="@{/js/bootstrap.bundle.min.js}"></script>
    <script th:src="@{/js/flv.min.js}"></script>
    <script th:src="@{/js/hls.min.js}"></script>
    
    <script>
        // 全局变量
        let flvPlayer = null;
        let hlsPlayer = null;
        const apiBaseUrl = '/api';
        
        $(document).ready(function() {
            // 初始化Bootstrap标签
            const tabEls = document.querySelectorAll('button[data-bs-toggle="tab"]')
            tabEls.forEach(tabEl => {
                tabEl.addEventListener('click', event => {
                    event.preventDefault();
                    const tabTarget = document.querySelector(event.target.getAttribute('data-bs-target'));
                    
                    // 移除所有标签页的active类
                    document.querySelectorAll('.tab-pane').forEach(pane => {
                        pane.classList.remove('show', 'active');
                    });
                    document.querySelectorAll('.nav-link').forEach(link => {
                        link.classList.remove('active');
                    });
                    
                    // 将当前标签页设为active
                    event.target.classList.add('active');
                    tabTarget.classList.add('show', 'active');
                });
            });
            
            // 初始化加载数据
            loadStreams();
            loadRecordings();
            loadServerStatus();
            
            // 刷新按钮事件
            $('#refresh-streams').click(loadStreams);
            $('#refresh-recordings').click(loadRecordings);
            $('#refresh-status').click(loadServerStatus);
            
            // 播放按钮事件
            $('#playBtn').click(function() {
                const url = $('#videoUrl').val();
                if (!url) {
                    alert('请输入视频 URL');
                    return;
                }
                
                const playerType = $('input[name="playerType"]:checked').val();
                playVideo(url, playerType);
            });
            
            // 停止按钮事件
            $('#stopBtn').click(function() {
                destroyPlayers();
                $('#videoPlayer').attr('src', '');
            });
        });
        
        // 加载当前在线推流流
        function loadStreams() {
            $.get(apiBaseUrl + '/streams', function(data) {
                const container = $('#streams-container');
                container.empty();
                
                if (data.success && data.streams && data.streams.length > 0) {
                    $('#no-streams').hide();
                    
                    data.streams.forEach(stream => {
                        const streamKey = stream.streamKey;
                        const hlsUrl = `/live/${streamKey}/index.m3u8`;
                        
                        const streamItem = `
                            <div class="col-md-6 col-lg-4 mb-4">
                                <div class="card">
                                    <div class="card-body">
                                        <h5 class="card-title">${streamKey}</h5>
                                        <p class="card-text">
                                            <strong>开始时间:</strong> ${new Date(stream.startTime).toLocaleString()}<br>
                                            <strong>时长:</strong> ${formatDuration(stream.durationInSeconds)}
                                        </p>
                                        <button class="btn btn-sm btn-primary watch-stream" data-url="${hlsUrl}">观看</button>
                                        <a href="${hlsUrl}" class="btn btn-sm btn-secondary" target="_blank">直接访问</a>
                                    </div>
                                </div>
                            </div>
                        `;
                        
                        container.append(streamItem);
                    });
                    
                    // 观看推流按钮点击事件
                    $('.watch-stream').click(function() {
                        const url = $(this).data('url');
                        $('#videoUrl').val(url);
                        $('input[name="playerType"][value="hls"]').prop('checked', true);
                        $('#player-tab').tab('show');
                        playVideo(url, 'hls');
                    });
                    
                } else {
                    $('#no-streams').show();
                }
            }).fail(function() {
                $('#no-streams').show().text('加载失败，请刷新重试');
            });
        }
        
        // 加载录像回放列表
        function loadRecordings() {
            $.get(apiBaseUrl + '/recordings', function(data) {
                const container = $('#recordings-container');
                container.empty();
                
                if (data.success && data.recordings && data.recordings.length > 0) {
                    $('#no-recordings').hide();
                    
                    data.recordings.forEach(recording => {
                        const recordingUrl = recording.url;
                        
                        const recordingItem = `
                            <div class="recording-item">
                                <h5>${recording.fileName}</h5>
                                <p>
                                    <strong>流名称:</strong> ${recording.streamKey}<br>
                                    <strong>创建时间:</strong> ${new Date(recording.createdTime).toLocaleString()}<br>
                                    <strong>大小:</strong> ${formatFileSize(recording.fileSize)}<br>
                                    <strong>预计时长:</strong> ${formatDuration(recording.durationInSeconds)}
                                </p>
                                <div class="btn-group">
                                    <button class="btn btn-sm btn-primary watch-recording" data-url="${recordingUrl}">观看</button>
                                    <a href="${recordingUrl}" class="btn btn-sm btn-secondary" download>下载</a>
                                    <button class="btn btn-sm btn-danger delete-recording" data-id="${recording.id}">删除</button>
                                </div>
                            </div>
                        `;
                        
                        container.append(recordingItem);
                    });
                    
                    // 观看录像按钮点击事件
                    $('.watch-recording').click(function() {
                        const url = $(this).data('url');
                        $('#videoUrl').val(url);
                        $('input[name="playerType"][value="flv"]').prop('checked', true);
                        $('#player-tab').tab('show');
                        playVideo(url, 'flv');
                    });
                    
                    // 删除录像按钮点击事件
                    $('.delete-recording').click(function() {
                        const id = $(this).data('id');
                        if (confirm(`确定要删除这个录像吗？`)) {
                            deleteRecording(id);
                        }
                    });
                    
                } else {
                    $('#no-recordings').show();
                }
            }).fail(function() {
                $('#no-recordings').show().text('加载失败，请刷新重试');
            });
        }
        
        // 删除录像
        function deleteRecording(id) {
            $.ajax({
                url: apiBaseUrl + '/recordings/' + id,
                method: 'DELETE',
                success: function(response) {
                    if (response.success) {
                        alert('删除成功');
                        loadRecordings();
                    } else {
                        alert('删除失败: ' + response.error);
                    }
                },
                error: function() {
                    alert('请求失败，请重试');
                }
            });
        }
        
        // 加载服务器状态
        function loadServerStatus() {
            $.get(apiBaseUrl + '/streams/stats', function(data) {
                if (data.success) {
                    const stats = data.stats;
                    
                    const statusHtml = `
                        <p><strong>活动推流流数量:</strong> ${stats.activeStreams}</p>
                        <p><strong>正在录制流数量:</strong> ${stats.recordingSessions}</p>
                        <p><strong>RTMP会话数量:</strong> ${stats.rtmpSessions}</p>
                        <p><strong>当前时间:</strong> ${new Date().toLocaleString()}</p>
                    `;
                    
                    $('#server-info').html(statusHtml);
                }
            }).fail(function() {
                $('#server-info').html('加载服务器状态失败，请刷新重试');
            });
        }
        
        // 播放视频
        function playVideo(url, type) {
            // 销毁现有播放器
            destroyPlayers();
            
            const videoElement = document.getElementById('videoPlayer');
            
            if (type === 'flv') {
                if (flvjs.isSupported()) {
                    flvPlayer = flvjs.createPlayer({
                        type: 'flv',
                        url: url
                    });
                    flvPlayer.attachMediaElement(videoElement);
                    flvPlayer.load();
                    flvPlayer.play();
                } else {
                    alert('您的浏览器不支持 FLV 播放');
                }
            } else if (type === 'hls') {
                if (Hls.isSupported()) {
                    hlsPlayer = new Hls();
                    hlsPlayer.loadSource(url);
                    hlsPlayer.attachMedia(videoElement);
                    hlsPlayer.on(Hls.Events.MANIFEST_PARSED, function() {
                        videoElement.play();
                    });
                } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
                    // 原生HLS支持（Safari）
                    videoElement.src = url;
                    videoElement.addEventListener('loadedmetadata', function() {
                        videoElement.play();
                    });
                } else {
                    alert('您的浏览器不支持 HLS 播放');
                }
            }
        }
        
        // 销毁现有播放器
        function destroyPlayers() {
            if (flvPlayer) {
                flvPlayer.unload();
                flvPlayer.detachMediaElement();
                flvPlayer.destroy();
                flvPlayer = null;
            }
            
            if (hlsPlayer) {
                hlsPlayer.destroy();
                hlsPlayer = null;
            }
        }
        
        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
        
        // 格式化时长
        function formatDuration(seconds) {
            const hours = Math.floor(seconds / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            const secs = Math.floor(seconds % 60);
            
            return [
                hours.toString().padStart(2, '0'),
                minutes.toString().padStart(2, '0'),
                secs.toString().padStart(2, '0')
            ].join(':');
        }
    </script>
</body>
</html> 